package mutation;


import ga.Individual;
import instrumentation.Condition;

import java.util.List;
import java.util.Map;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.Collections;
import mdr.RecommendGenerator;
import model.StatementKind;
import operations.Operation;
import operations.CreateObject;
import operations.InvokeMethod;
import operations.ValuesGenerator;
import util.DebugConfig;
import util.GAConfig;
import util.Log;
import util.Randomness;

public class CopyOfMDRDeleteMethodCall extends MutationStrategy {

	@Override
	public Individual mutate(Individual individual) {
		if(DebugConfig.deleteRandomMethodClass){
			Log.log("-------  Delete Random Method Call Mutation ---------------"); 
			Log.log("--------------------individual1----------------------");
			Log.log(individual.toString()+ " size:"+ individual.getSize());
		}
		long totalMutation=this.gaInfo.getTotalMutationDelete();
		RecommendGenerator recommendGenerator=this.gaInfo.getRecommendGenerator();
		Integer trgtBR=-1;
		if(GAConfig.TargetHitBranches)
			trgtBR=MutationFactory.getHitTargetToCover(this.gaInfo);
		else
				trgtBR=MutationFactory.getTargetToCover(this.gaInfo);
//		System.out.println("MDRDeleteMethodCall trgtBR: "+ trgtBR);//+ " " +recommendGenerator.getBranchWithData(trgtBR));
		
		
		 List<StatementKind>  BRRelatedStatementList=recommendGenerator.getRecommendMethodsBranch(trgtBR);
//		System.out.println("MDRDeleteMethodCall trgtBR: "+ trgtBR+ " " +BRRelatedStatementList);
		if(BRRelatedStatementList.size()==0)
			return individual;

		//add method that contains the target		
//		List<Class<?>> recClassToTest= new ArrayList<Class<?>>(BRRelatedStatementList.keySet());
//		Class<?> clz=recClassToTest.get(ValuesGenerator.getRandomIntBetween(0,recClassToTest.size()-1));
//		List<StatementKind> statements=BRRelatedStatementList.get(clz);
		
		if(BRRelatedStatementList.size()==0){
			System.err.println("MDRDeleteMethodCall: There are no method to recommend!");
			System.exit(1);
		}
		// choose a writing method to delete!
		int randMethod = Randomness.nextRandomInt(BRRelatedStatementList.size());
		StatementKind st=BRRelatedStatementList.get(randMethod);

		Individual mutatedIndividual=individual.clone();
		List<Operation> ops =mutatedIndividual.getStatements();

		try {
			List<StatementKind> methodList= new LinkedList<StatementKind>();
			methodList.addAll(BRRelatedStatementList);
			methodList.removeAll(Collections.singleton(st));

			List<Operation> newOps = new LinkedList<Operation>();
	
			//remove operations from the individual
			//int num = Randomness.nextRandomInt(10);
			for(Operation op : ops) {

				if (getMutationFlag(ops.size()))
					continue;
				if (op instanceof CreateObject&&(BRRelatedStatementList.size()!=1)){
						 if(st.equals(((CreateObject)op).getConstructor())&& getMutationFlag(2))
							 continue;
					}
		  	    else if(op instanceof InvokeMethod&&(BRRelatedStatementList.size()!=1)){
					 if(st.equals(((InvokeMethod)op).getMethod())&& getMutationFlag(2))
						 continue;
					 }
				newOps.add(op);
				totalMutation++;
			}
			
			if(newOps.size()!=0){
				ops.clear();
				ops.addAll(newOps);
			}
			this.gaInfo.setTotalMutationDelete(totalMutation);
			return mutatedIndividual;
		} catch (Throwable e){
			System.err.println("Delete Random Method Call Class:" + e.getMessage());
		}	
		return null;
		
	}

	@Override
	public boolean getMutationFlag(int size) {
		float mutationRate=1.0f/size;
		if(GAConfig.mutation_rate!=0f)
			mutationRate=GAConfig.mutation_rate;
		if(ValuesGenerator.getBoolean(mutationRate))
			return true;
		return false;

	}
}
